/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Algoritmo;

import Controlador.GestorInterseccion;
import Modelo.Interseccion;
import Modelo.Universo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
//import org.jgap.*;

/**
 *
 * @author javier
 */
public class Genetico extends Algoritmo {

    {
        /*
         int numeroIndividuosInicial;
         ArrayList<Individuo> individuosIniciales;
    
    
         //Javier : GestorInterseccion equivale a matriz de una zona
         public Genetico(GestorInterseccion gI){ 
        
         //LlenarPobladoresIniciales;
         individuosIniciales = transformarMatrizAArreglo(gI);
        
         //Contabilizamos
         numeroIndividuosInicial = individuosIniciales.size();
        
         }
    
         private ArrayList<Individuo> transformarMatrizAArreglo(GestorInterseccion gI){
         return null;
         }
    
         //Jav: metodo que genera configuraciones aleatorias a las intersecciones
         public ArrayList<Individuo> GenerarSolucionAlternativa(){
         ArrayList<Individuo> respuesta = new ArrayList<Individuo>();
         Universo u = Universo.GetInstance();
         int limite = u.GetCantidadConfiguracionesPosibles();
         for (int i=0; i< numeroPobladoresInicial; i++){
         int x = 0 + (int) (Math.random() * limite);
            
         }
         }
         }
         */
    }

    ArrayList<Gen> IndividuoInicial;
    ArrayList<ArrayList<Gen>> PoblacionInicial;
    ArrayList<ArrayList<Gen>> SiguienteGeneracion;
    ArrayList<ArrayList<Gen>> PoblacionSeleccionada;
    ArrayList<Gen> IndividuoOptimo;
    int NumeroGeneracionesMaximo = 10;

    public Genetico(Interseccion[][] zona) {
        int corte = 3;
        IndividuoInicial = ConvertirZonaAIndividuo(zona);
        PoblacionInicial = GenerarPoblacionInicial(IndividuoInicial, zona);
        int contador = 0;
        while (contador < NumeroGeneracionesMaximo) {
//            System.out.println("POBLACION INICIAL");
//            ImprimirPoblacion(PoblacionInicial);
            SiguienteGeneracion = Cruce(PoblacionInicial, PoblacionInicial.size() / 2);
//            System.out.println("SIGUIENTE GENERACION");
//            ImprimirPoblacion(SiguienteGeneracion);

            //Javier: Mutacion Pendiente para la SigguienteGeneracion;
            PoblacionSeleccionada = Seleccion(PoblacionInicial, SiguienteGeneracion);
//            System.out.println("POBLACION SELECIONADA");
//            ImprimirPoblacion(SiguienteGeneracion);
            contador++;
            if (contador < NumeroGeneracionesMaximo) {
                //Copiar(PoblacionSeleccionada,PoblacionInicial);
                PoblacionInicial = ClonarPoblacion(PoblacionSeleccionada);
            }
        }
        ImprimirZDeMejorIndividuo(PoblacionSeleccionada);
        //ImprimirIndividuoIesimoDePoblacion(1, PoblacionSeleccionada);
    }

    //==================== IMPRESIONES ==================================//
    private void ImprimirPoblacion(ArrayList<ArrayList<Gen>> p) {
        for (int i = 0; i < p.size(); i++) {
            ArrayList<Gen> indiv = p.get(i);
            System.out.print("Z=" + EvaluacionFuncionObjetivoUsandoIndividuo(indiv));
            for (int j = 0; j < IndividuoInicial.size(); j++) {
                Gen in = indiv.get(j);
                System.out.print("[" + in.getConfiguracion() + "] ");
            }
            System.out.println("");
        }
    }
    private void ImprimirZDeMejorIndividuo(ArrayList<ArrayList<Gen>> poblacion) {
        ArrayList<Gen> individuo = (ArrayList<Gen>) poblacion.get(0);
        int numeroGenes = individuo.size();/*
        for (int i = 0; i < numeroGenes; i++) {
            System.out.print("[" + individuo.get(i).getConfiguracion() + "] ");
        }*/
        System.out.println(EvaluacionFuncionObjetivoUsandoIndividuo(individuo));
    }

    private void ImprimirIndividuoIesimoDePoblacion(int dni, ArrayList<ArrayList<Gen>> poblacion) {
        ArrayList<Gen> individuo = (ArrayList<Gen>) poblacion.get(dni);
        int numeroGenes = individuo.size();
        for (int i = 0; i < numeroGenes; i++) {
            System.out.print("[" + individuo.get(i).getConfiguracion() + "] ");
        }
        System.out.println("\nZ=" + EvaluacionFuncionObjetivoUsandoIndividuo(individuo));
    }

    private void ImprimirConfiguracionInviduo(ArrayList<Gen> individuo) {
        int numeroGenes = individuo.size();
        System.out.print("INDIVIDUO : ");
        for (int i = 0; i < numeroGenes; i++) {
            System.out.print("[" + individuo.get(i).getConfiguracion() + "] ");
        }
    }

    private void ImprimirNumeroDeAutosInviduo(ArrayList<Gen> individuo) {
        int numeroGenes = individuo.size();
        System.out.print("INDIVIDUO : ");
        for (int i = 0; i < numeroGenes; i++) {
            Gen g = (Gen) individuo.get(i);
            int n = g.getnAutosEste() + g.getnAutosOeste() + g.getnAutosNorte() + g.getnAutosSur();
            System.out.print("[" + n + "] ");
        }
    }

    private void ImprimirNumeroDeAutosZona(Interseccion[][] zona, int largo, int ancho) {
        for (int i = 0; i < largo; i++) {
            System.out.println("N  +  E  +  S + O");
            for (int j = 0; j < ancho; j++) {
                if (zona[i][j] != null) {
                    System.out.print(zona[i][j].getnAutosNorte() + " - ");
                    System.out.print(zona[i][j].getnAutosEste() + " - ");
                    System.out.print(zona[i][j].getnAutosSur() + "\n");
                    System.out.print(zona[i][j].getnAutosOeste() + " - ");
                }
            }
            System.out.println();
        }
    }

    //========================================================================//
    //==========================CLONACIONES=====================================//
    private ArrayList<Gen> ClonarIndividuo(ArrayList<Gen> individuoOriginal) {
        int numeroDeGenes = individuoOriginal.size();
        ArrayList<Gen> nuevoIndividuo = new ArrayList<Gen>();
        for (int i = 0; i < numeroDeGenes; i++) {
            Gen nuevoGen = new Gen();
            Gen genOriginal = (Gen) individuoOriginal.get(i);

            nuevoGen.setPosX(genOriginal.getPosX());
            nuevoGen.setPosY(genOriginal.getPosY());
            nuevoGen.setnAutosEste(genOriginal.getnAutosEste());
            nuevoGen.setnAutosOeste(genOriginal.getnAutosOeste());
            nuevoGen.setnAutosNorte(genOriginal.getnAutosNorte());
            nuevoGen.setnAutosSur(genOriginal.getnAutosSur());
            nuevoGen.setConfiguracion(genOriginal.getConfiguracion());
            nuevoIndividuo.add(nuevoGen);
        }
        return nuevoIndividuo;
    }

    private ArrayList<ArrayList<Gen>> ClonarPoblacion(ArrayList<ArrayList<Gen>> poblacionOriginal) {
        ArrayList<ArrayList<Gen>> nuevaPoblacion = new ArrayList<ArrayList<Gen>>();
        int cantidadDeIndividuos = poblacionOriginal.size();
        ArrayList<Gen> nuevoIndividuo;
        ArrayList<Gen> originalIndividuo;
        for (int i = 0; i < cantidadDeIndividuos; i++) {
            nuevoIndividuo = new ArrayList<Gen>();
            originalIndividuo = (ArrayList<Gen>) poblacionOriginal.get(i);
            nuevoIndividuo = ClonarIndividuo(originalIndividuo);
            nuevaPoblacion.add(nuevoIndividuo);
        }
        return nuevaPoblacion;
    }
    //============================================================================//

    private ArrayList<ArrayList<Gen>> GenerarPoblacionInicial(ArrayList<Gen> rm, Interseccion[][] zona) {
        ArrayList<ArrayList<Gen>> rpta = new ArrayList<ArrayList<Gen>>();

        int numeroDeIndividuosDePoblacionInicial = 16 * IndividuoInicial.size();
        int numeroDeIntersecciones = IndividuoInicial.size();
        Universo u = Universo.GetInstance();
        int limite = u.GetCantidadConfiguracionesPosibles(); //Limite = 16

        for (int i = 0; i < numeroDeIndividuosDePoblacionInicial; i++) {
            ArrayList<Gen> individuo = new ArrayList<Gen>();
            for (int j = 0; j < numeroDeIntersecciones; j++) {
                Gen g = new Gen();// individuo.get(j);
                g.setPosX(rm.get(j).getPosX());
                g.setPosY(rm.get(j).getPosY());
                g.setnAutosEste(rm.get(j).getnAutosEste());
                g.setnAutosOeste(rm.get(j).getnAutosOeste());
                g.setnAutosNorte(rm.get(j).getnAutosNorte());
                g.setnAutosSur(rm.get(j).getnAutosSur());
                //Javier : esto es lo unico aleatorio
                int n = 1 + (int) (Math.random() * limite);
                g.setConfiguracion(n);
                //-----------------------------------
                individuo.add(g);
            }
            rpta.add(individuo);
            //
        }
        return rpta;
    }

    private ArrayList<ArrayList<Gen>> Cruce(ArrayList<ArrayList<Gen>> PoblacionInicial, int corte) {
        ArrayList<ArrayList<Gen>> retorno = new ArrayList<ArrayList<Gen>>();
        for (int i = 0; i < PoblacionInicial.size() / 2; i++) {
            ArrayList<Gen> hijo1 = GeneraHijo(PoblacionInicial.get(i), PoblacionInicial.get(PoblacionInicial.size() - i - 1), corte);
            ArrayList<Gen> hijo2 = GeneraHijo(PoblacionInicial.get(PoblacionInicial.size() - i - 1), PoblacionInicial.get(i), corte);
            retorno.add(hijo1);
            retorno.add(hijo2);
        }
        return retorno;
    }

    class valoracion {

        public ArrayList<Gen> individuo;
        public int z;

        public valoracion(ArrayList<Gen> individuo, int z) {
            this.z = z;
            this.individuo = ClonarIndividuo(individuo);
        }

    }

    private ArrayList<ArrayList<Gen>> Seleccion(ArrayList<ArrayList<Gen>> pobIni, ArrayList<ArrayList<Gen>> sigGeneracion) {

        ArrayList<ArrayList<Gen>> respuesta = new ArrayList<ArrayList<Gen>>();

        ArrayList<valoracion> pobTotalValorada = new ArrayList<valoracion>();
        //==========================================================================
        //Javier: Zona de evaluacion de individuos que se guardan en popTotalValorada
        int z;
        valoracion v;
        for (int i = 0; i < PoblacionInicial.size(); i++) {
            z = EvaluacionFuncionObjetivoUsandoIndividuo(pobIni.get(i));
            v = new valoracion(pobIni.get(i), z);
            pobTotalValorada.add(v);

            z = EvaluacionFuncionObjetivoUsandoIndividuo(sigGeneracion.get(i));
            v = new valoracion(sigGeneracion.get(i), z);
            pobTotalValorada.add(v);
        }
        //==========================================================================
        //Javier: ordenamiento
        Collections.sort(pobTotalValorada, new Comparator<valoracion>() {
            @Override
            /*hola*/
            public int compare(valoracion o1, valoracion o2) {
                int rpta =0;
                if (o1.z == o2.z) {
                    rpta=0;
                } else {
                    if (o1.z < o2.z) {
                        rpta = -1;
                    } else {
                        rpta = +1;
                    };
                }
                return rpta;
            }
        });
        //==========================================================================
        //Javier: RULETA o supervivencia, solo se quedan los mejorcitos
        int mitad = pobTotalValorada.size() / 2;
        int tamanioTotal = pobTotalValorada.size();
        for (int i = tamanioTotal - 1; i >= mitad; i--) {
            pobTotalValorada.remove(i);
        }
        //==========================================================================
        //Javier: ahora lo que ya esta valorado se puede copiar a una poblacion para
        //la siguiente generación
        int cantidadDeIndividuos = pobTotalValorada.size();
        ArrayList<Gen> nuevoIndividuo;
        ArrayList<Gen> originalIndividuo;
        for (int i = 0; i < cantidadDeIndividuos; i++) {
            nuevoIndividuo = new ArrayList<Gen>();
            originalIndividuo = pobTotalValorada.get(i).individuo;
            nuevoIndividuo = ClonarIndividuo(originalIndividuo);
            respuesta.add(nuevoIndividuo);
        }
        //==========================================================================
        return respuesta;
    }

    private ArrayList<Gen> GeneraHijo(ArrayList<Gen> get, ArrayList<Gen> get0, int corte) {
        ArrayList<Gen> retorno = new ArrayList<Gen>();

        for (int i = 0; i < get.size(); i++) {
            if (i < corte) {
                retorno.add(get.get(i));
            } else {
                retorno.add(get0.get(i));
            }
        }
        return retorno;
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

}
